﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition.Primitives;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition;

namespace FluentMef
{
    public sealed class ContainerBuilder : ComposablePartCatalog, IContainerBuilder, ICompositionElement
    {
        readonly Dictionary<string, IComposablePartDefinitionBuilder> _parts = new Dictionary<string,IComposablePartDefinitionBuilder>();
        volatile IQueryable<ComposablePartDefinition> _queryableParts;
        readonly object _thisLock = new object();

        public void Attributed<T>()
        {
            throw new NotImplementedException();
        }

        public void Attributed<T>(string contractName)
        {
            throw new NotImplementedException();
        }

        public IExportExpression<T> For<T>()
        {
            var identity = ContractNameServices.GetTypeIdentity(typeof(T));
            return new ExportExpression<T>(this, identity, identity, (newBuilder) => _parts[identity] = newBuilder);
        }

        public IExportExpression<T> For<T>(string contractName)
        {
            if(string.IsNullOrWhiteSpace(contractName)) throw new ArgumentNullException("contractName");

            return new ExportExpression<T>(this, contractName, ContractNameServices.GetTypeIdentity(typeof(T)), (newBuilder) => _parts[contractName] = newBuilder);
        }

        internal CompositionContainer CreateContainer()
        {
            return new CompositionContainer(this);    
        }

        string ICompositionElement.DisplayName
        {
            get { return "ContainerBuilder"; }
        }

        ICompositionElement ICompositionElement.Origin
        {
            get { return null; }
        }

        public override IQueryable<ComposablePartDefinition> Parts
        {
            get 
            {
                if (_queryableParts == null)
                {
                    lock (_thisLock)
                    {
                        if (_queryableParts == null)
                        {
                            var source = new List<ComposablePartDefinition>();

                            foreach (var builder in _parts.Values)
                            {
                                source.Add(builder.BuildDefinition());
                            }

                            _queryableParts = source.AsQueryable();
                        }
                    }
                }
                return _queryableParts;
            }
        }
    }
}
